package org.xx.armory.db.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xx.armory.commons.AbstractLifeCycle;
import org.xx.armory.db.SessionFactory;
import org.xx.armory.db.TransactionManager;

import javax.sql.DataSource;

import static org.xx.armory.commons.Validators.notNull;

/**
 * 提供了会话工厂的基本实现。
 * <p>
 * <strong>此类型不是线程安全的，如果要多个线程中使用，可以通过 {@code SessionFactory#fork()} 方法复制一个新的会话工厂。</strong>
 * </p>
 *
 * @author Haart
 */
public abstract class AbstractSessionFactory
        extends AbstractLifeCycle
        implements SessionFactory {
    @SuppressWarnings("unused")
    private final Logger logger = LoggerFactory.getLogger(SessionFactory.class);
    private DataSource dataSource;
    private TransactionManager transactionManager;
    /**
     * 标志是否使用了外部的事务管理器。
     */
    private boolean externalTransactionManager;

    /**
     * 构造抽象会话工厂对象。
     */
    public AbstractSessionFactory() {
        // 默认使用本地事务管理器。
        this.transactionManager = new LocalTransactionManager();
        externalTransactionManager = false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setDataSource(
            DataSource dataSource
    ) {
        assertNotInitialized();

        notNull(dataSource, "dataSource");

        this.dataSource = dataSource;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final TransactionManager getTransactionManager() {
        return transactionManager;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void setTransactionManager(
            TransactionManager transactionManager
    ) {
        assertNotInitialized();

        notNull(transactionManager, "transactionManager");

        if (this.transactionManager != transactionManager) {
            // 注入外部事务管理器。
            this.transactionManager = transactionManager;
            externalTransactionManager = true;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize()
            throws Exception {
        super.initialize();

        if (!externalTransactionManager) {
            // 如果没有设置外部事务管理器，那么自动注入数据源。
            this.transactionManager.setDataSource(this.dataSource);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void dispose()
            throws Exception {
        super.dispose();

        // 如果没有从外部设置事务处理器，那么当前事务处理器是默认的本地事务处理器。
        // 如果默认的本地事务处理器是可以被关闭的，那么关闭它。
        if (!externalTransactionManager && this.transactionManager instanceof AutoCloseable) {
            ((AutoCloseable) this.transactionManager).close();
        }
    }

    /**
     * 复制自身到另一个会话工厂。
     *
     * @param other
     *         另一个会话工厂。
     * @throws IllegalArgumentException
     *         如果参数{@code other}是{@code null}。
     */
    protected void forkTo(
            SessionFactory other
    ) {
        other.setDataSource(this.dataSource);
    }
}
